home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1993 July / Internet Tools.iso / RockRidge / mail / elm / elm2.4 / src / sort.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-04-11  |  10.5 KB  |  317 lines

  1.  
  2. static char rcsid[] = "@(#)$Id: sort.c,v 5.2 1993/04/12 03:42:56 syd Exp $";
  3.  
  4. /*******************************************************************************
  5.  *  The Elm Mail System  -  $Revision: 5.2 $   $State: Exp $
  6.  *
  7.  *            Copyright (c) 1988-1992 USENET Community Trust
  8.  *            Copyright (c) 1986,1987 Dave Taylor
  9.  *******************************************************************************
  10.  * Bug reports, patches, comments, suggestions should be sent to:
  11.  *
  12.  *    Syd Weinstein, Elm Coordinator
  13.  *    elm@DSI.COM            dsinc!elm
  14.  *
  15.  *******************************************************************************
  16.  * $Log: sort.c,v $
  17.  * Revision 5.2  1993/04/12  03:42:56  syd
  18.  * I noticed when I was sorting a mailbox by subject, that 2 messages with
  19.  * the following subjects
  20.  *
  21.  *     Subject: Re: Reading news
  22.  *     Subject: Reading news
  23.  *
  24.  * they were sorted as shown above even though the "Re:" message was
  25.  * "Sent" after the original.  It turns out that the routine skip_re has a
  26.  * bug.  If the actual subject (the part after the "Re: ") starts with the
  27.  * characters "re" skip_re will erroneously not strip the "Re:" part at
  28.  * all.  The following patch fixes that behaviour.
  29.  * From: Larry Philps <larryp@sco.COM>
  30.  *
  31.  * Revision 5.1  1992/10/03  22:58:40  syd
  32.  * Initial checkin as of 2.4 Release at PL0
  33.  *
  34.  *
  35.  ******************************************************************************/
  36.  
  37. /** Sort folder header table by the field specified in the global
  38.     variable "sortby"...if we're sorting by something other than
  39.     the default SENT_DATE, also put some sort of indicator on the
  40.     screen.
  41.  
  42. **/
  43.  
  44. #include "headers.h"
  45. #include "s_elm.h"
  46.  
  47. char *sort_name(), *skip_re();
  48.  
  49. void
  50. find_old_current(iindex)
  51. int iindex;
  52. {
  53.     /** Set current to the message that has "index" as it's 
  54.         index number.  This is to track the current message
  55.         when we resync... **/
  56.  
  57.     register int i;
  58.  
  59.     dprint(4, (debugfile, "find-old-current(%d)\n", iindex));
  60.  
  61.     for (i = 0; i < message_count; i++)
  62.       if (headers[i]->index_number == iindex) {
  63.         current = i+1;
  64.         dprint(4, (debugfile, "\tset current to %d!\n", current));
  65.         return;
  66.       }
  67.  
  68.     dprint(4, (debugfile, 
  69.         "\tcouldn't find current index.  Current left as %d\n",
  70.         current));
  71.     return;        /* can't be found.  Leave it alone, then */
  72. }
  73.  
  74. sort_mailbox(entries, visible)
  75. int entries, visible;
  76. {
  77.     /** Sort the header_table definitions... If 'visible', then
  78.         put the status lines etc **/
  79.     
  80.     int last_index = -1;
  81.     int compare_headers();    /* for sorting */
  82.  
  83.     dprint(2, (debugfile, "\n** sorting folder by %s **\n\n", 
  84.         sort_name(FULL)));
  85.  
  86.     /* Don't get last_index if no entries or no current. */
  87.     /* There would be no current if we are sorting a new mail file. */
  88.     if (entries > 0 && current > 0)
  89.       last_index = headers[current-1]->index_number;
  90.  
  91.     if (entries > 30 && visible)  
  92.       error1(catgets(elm_msg_cat, ElmSet, ElmSortingMessagesBy, 
  93.         "Sorting messages by %s..."), sort_name(FULL));
  94.     
  95.     if (entries > 1)
  96.       qsort((char *) headers, (unsigned) entries,
  97.           sizeof (struct header_rec *) , compare_headers);
  98.  
  99.     if (last_index > -1)
  100.       find_old_current(last_index);
  101.  
  102.     clear_error();
  103. }
  104.  
  105. int
  106. compare_headers(p1, p2)
  107. struct header_rec **p1, **p2;
  108. {
  109.     /** compare two headers according to the sortby value.
  110.  
  111.         Sent Date uses a routine to compare two dates,
  112.         Received date is keyed on the file offsets (think about it)
  113.         Sender uses the truncated from line, same as "build headers",
  114.         and size and subject are trivially obvious!!
  115.         (actually, subject has been modified to ignore any leading
  116.         patterns [rR][eE]*:[ \t] so that replies to messages are
  117.         sorted with the message (though a reply will always sort to
  118.         be 'greater' than the basenote)
  119.      **/
  120.  
  121.     char from1[SLEN], from2[SLEN];    /* sorting buffers... */
  122.     struct header_rec *first, *second;
  123.     int ret;
  124.     long diff;
  125.     
  126.     first = *p1;
  127.     second = *p2;
  128.  
  129.     switch (abs(sortby)) {
  130.     case SENT_DATE:
  131.          diff = first->time_sent - second->time_sent;
  132.          if ( diff < 0 )    ret = -1;
  133.          else if ( diff > 0 ) ret = 1;
  134.          else ret = 0;
  135.           break;
  136.  
  137.     case RECEIVED_DATE:
  138.          diff = first->received_time - second->received_time;
  139.          if ( diff < 0 )    ret = -1;
  140.          else if ( diff > 0 ) ret = 1;
  141.          else ret = 0;
  142.           break;
  143.  
  144.     case SENDER:
  145.         tail_of(first->from, from1, first->to);
  146.         tail_of(second->from, from2, second->to);
  147.         ret = strcmp(from1, from2);
  148.         break;
  149.  
  150.     case SIZE:
  151.         ret = (first->lines - second->lines);
  152.         break;
  153.  
  154.     case MAILBOX_ORDER:
  155.         ret = (first->index_number - second->index_number);
  156.         break;
  157.  
  158.     case SUBJECT:
  159.         /* need some extra work 'cause of STATIC buffers */
  160.         strcpy(from1, skip_re(shift_lower(first->subject)));
  161.         ret = strcmp(from1, skip_re(shift_lower(second->subject)));
  162.         break;
  163.  
  164.     case STATUS:
  165.         ret = (first->status - second->status);
  166.         break;
  167.  
  168.     default:
  169.         /* never get this! */
  170.         ret = 0;
  171.         break;
  172.     }
  173.  
  174.     /* on equal status, use sent date as second sort param. */
  175.     if (ret == 0) {
  176.         diff = first->time_sent - second->time_sent;
  177.         if ( diff < 0 )    ret = -1;
  178.         else if ( diff > 0 ) ret = 1;
  179.         else ret = 0;
  180.     }
  181.  
  182.     if (sortby < 0)
  183.       ret = -ret;
  184.  
  185.     return ret;
  186. }
  187.  
  188. char *sort_name(type)
  189. int type;
  190. {
  191.     /** return the name of the current sort option...
  192.         type can be "FULL", "SHORT" or "PAD"
  193.     **/
  194.     int pad, abr;
  195.     
  196.     pad = (type == PAD);
  197.     abr = (type == SHORT);
  198.  
  199.     if (sortby < 0) {
  200.       switch (- sortby) {
  201.         case SENT_DATE    : return( 
  202.                       pad?     catgets(elm_msg_cat, ElmSet, ElmPadRevDateMailSent, "Reverse Date Mail Sent  ") : 
  203.                   abr?     catgets(elm_msg_cat, ElmSet, ElmAbrtRevDateMailSent, "Reverse-Sent") :
  204.                        catgets(elm_msg_cat, ElmSet, ElmLongRevDateMailSent, "Reverse Date Mail Sent"));
  205.         case RECEIVED_DATE: return(
  206.                   pad?     catgets(elm_msg_cat, ElmSet, ElmPadRevRecv, "Reverse Date Mail Rec'vd") :
  207.                   abr?     catgets(elm_msg_cat, ElmSet, ElmAbrRevRecv, "Reverse-Received"):
  208.                        catgets(elm_msg_cat, ElmSet, ElmLongRevRecv, "Reverse Date Mail Rec'vd"));
  209.  
  210.         case MAILBOX_ORDER: return(
  211.                   pad?     catgets(elm_msg_cat, ElmSet, ElmPadRevMailbox, "Reverse Mailbox Order   ") :
  212.                   abr?     catgets(elm_msg_cat, ElmSet, ElmAbrRevMailbox, "Reverse-Mailbox"):
  213.                            catgets(elm_msg_cat, ElmSet, ElmLongRevMailbox, "Reverse Mailbox Order"));
  214.  
  215.         case SENDER       : return(
  216.                   pad?     catgets(elm_msg_cat, ElmSet, ElmPadRevSender, "Reverse Message Sender  ") : 
  217.                   abr?     catgets(elm_msg_cat, ElmSet, ElmAbrRevSender, "Reverse-From"):
  218.                        catgets(elm_msg_cat, ElmSet, ElmLongRevSender, "Reverse Message Sender"));
  219.         case SIZE         : return(
  220.                   pad?     catgets(elm_msg_cat, ElmSet, ElmPadRevLines, "Reverse Lines in Message") :
  221.                   abr?     catgets(elm_msg_cat, ElmSet, ElmAbrRevLines, "Reverse-Lines") : 
  222.                        catgets(elm_msg_cat, ElmSet, ElmLongRevLines, "Reverse Lines in Message"));
  223.         case SUBJECT      : return(
  224.                   pad?     catgets(elm_msg_cat, ElmSet, ElmPadRevSubject, "Reverse Message Subject ") : 
  225.                   abr?     catgets(elm_msg_cat, ElmSet, ElmAbrRevSubject, "Reverse-Subject") : 
  226.                        catgets(elm_msg_cat, ElmSet, ElmLongRevSubject, "Reverse Message Subject"));
  227.         case STATUS          : return(
  228.                   pad?     catgets(elm_msg_cat, ElmSet, ElmPadRevStatus, "Reverse Message Status  ") :
  229.                   abr?     catgets(elm_msg_cat, ElmSet, ElmAbrRevStatus, "Reverse-Status"):
  230.                            catgets(elm_msg_cat, ElmSet, ElmLongRevStatus, "Reverse Message Status"));
  231.       }
  232.     }
  233.     else {
  234.       switch (sortby) {
  235.         case SENT_DATE    : return( 
  236.                         pad?   catgets(elm_msg_cat, ElmSet, ElmPadMailSent, "Date Mail Sent          ") : 
  237.                         abr?   catgets(elm_msg_cat, ElmSet, ElmAbrMailSent, "Sent") : 
  238.                        catgets(elm_msg_cat, ElmSet, ElmLongMailSent, "Date Mail Sent"));
  239.         case RECEIVED_DATE: return(
  240.                             pad?   catgets(elm_msg_cat, ElmSet, ElmPadMailRecv, "Date Mail Rec'vd        ") :
  241.                             abr?   catgets(elm_msg_cat, ElmSet, ElmAbrMailRecv, "Received") :
  242.                        catgets(elm_msg_cat, ElmSet, ElmLongMailRecv, "Date Mail Rec'vd"));
  243.         case MAILBOX_ORDER: return(
  244.                             pad?   catgets(elm_msg_cat, ElmSet, ElmPadMailbox, "Mailbox Order           ") :
  245.                             abr?   catgets(elm_msg_cat, ElmSet, ElmAbrMailbox, "Mailbox") :
  246.                                    catgets(elm_msg_cat, ElmSet, ElmLongMailbox, "Mailbox Order"));
  247.         case SENDER       : return(
  248.                     pad?   catgets(elm_msg_cat, ElmSet, ElmPadSender, "Message Sender          ") : 
  249.                     abr?   catgets(elm_msg_cat, ElmSet, ElmAbrSender, "From") : 
  250.                        catgets(elm_msg_cat, ElmSet, ElmLongSender, "Message Sender"));
  251.         case SIZE         : return(
  252.                     pad?   catgets(elm_msg_cat, ElmSet, ElmPadLines, "Lines in Message        ") :
  253.                     abr?   catgets(elm_msg_cat, ElmSet, ElmAbrLines, "Lines") :
  254.                            catgets(elm_msg_cat, ElmSet, ElmLongLines, "Lines in Message"));
  255.         case SUBJECT      : return(
  256.                     pad?   catgets(elm_msg_cat, ElmSet, ElmPadSubject, "Message Subject         ") : 
  257.                     abr?   catgets(elm_msg_cat, ElmSet, ElmAbrSubject, "Subject") : 
  258.                        catgets(elm_msg_cat, ElmSet, ElmLongSubject, "Message Subject"));
  259.         case STATUS          : return(
  260.                     pad?   catgets(elm_msg_cat, ElmSet, ElmPadStatus, "Message Status          ") :
  261.                     abr?   catgets(elm_msg_cat, ElmSet, ElmAbrStatus, "Status") :
  262.                            catgets(elm_msg_cat, ElmSet, ElmLongStatus, "Message Status"));
  263.       }
  264.     }
  265.  
  266.     return(catgets(elm_msg_cat, ElmSet, ElmSortUnknown, "*UNKNOWN-SORT-PARAMETER*"));
  267. }
  268.  
  269. char *skip_re(string)
  270. char *string;
  271. {
  272.     /** this routine returns the given string minus any sort of
  273.         "re:" prefix.  specifically, it looks for, and will
  274.         remove, any of the pattern:
  275.  
  276.         ( [Rr][Ee][^:]:[ ] ) *
  277.  
  278.         If it doesn't find a ':' in the line it will return it
  279.         intact, just in case!
  280.     **/
  281.  
  282.     static char buffer[SLEN];
  283.     register int i=0;
  284.  
  285.     while (whitespace(string[i])) i++;
  286.  
  287.     /* Initialize buffer */
  288.     strcpy(buffer, (char *) string);
  289.  
  290.     do {
  291.       if (string[i] == '\0') return( (char *) buffer);    /* forget it */
  292.  
  293.       if (string[i] != 'r' || string[i+1] != 'e') 
  294.         return( (char *) buffer);                /*   ditto   */
  295.  
  296.       i += 2;    /* skip the "re" */
  297.  
  298.       while (string[i] != ':') 
  299.         if (string[i] == '\0')
  300.           return( (char *) buffer);              /* no colon in string! */
  301.         else
  302.           i++;
  303.  
  304.       /* now we've gotten to the colon, skip to the next non-whitespace  */
  305.  
  306.       i++;    /* past the colon */
  307.  
  308.       while (whitespace(string[i])) i++;
  309.  
  310.       /* Now save the resulting subject for return purposes */
  311.       strcpy(buffer, (char *) string + i);
  312.  
  313.     } while (string[i] == 'r' && string[i+1] == 'e');
  314.  
  315.     return( (char *) buffer);
  316. }
  317.